#ifndef SRC_BASE_CLOSURE_H
#define SRC_BASE_CLOSURE_H

#include "base/macro_def.h"

class Closure {
  public:
    virtual void Run() = 0;

    virtual ~Closure() {
    }

  protected:
    Closure() {
    }

  private:
    DISALLOW_COPY_AND_ASSIGN(Closure);
};

class StopableClosure : public Closure {
  public:
    explicit StopableClosure(Closure* c)
        : closure_(c), exit_(false) {
    }

    void Run() {
      while (!exit_) {
        closure_->Run();
      }
    }

    void Stop() {
      exit_ = true;
    }

  private:
    scoped_ptr<Closure> closure_;
    bool exit_;

    DISALLOW_COPY_AND_ASSIGN(StopableClosure);
};

class FuncClosure0 : public Closure {
    typedef void (*func)();

  public:
    explicit FuncClosure0(func f, bool self_del = false)
        : f_(f), self_del_(self_del) {
      CHECK_NOTNULL(f_);
    }

    ~FuncClosure0() {
      if (self_del_) delete this;
    }

    void Run() {
      f_();
    }

  private:
    func f_;
    bool self_del_;

    DISALLOW_COPY_AND_ASSIGN(FuncClosure0);
};

template<typename Type>
class FuncClosure1 : public Closure {
    typedef void (*func)(Type*);

  public:
    FuncClosure1(func f, Type* arg, bool self_del = false)
        : f_(f), self_del_(self_del), arg_(arg) {
    }

    ~FuncClosure1() {
      if (self_del_) delete this;
    }

    void Run() {
      CHECK_NOTNULL(f_);
      f_(arg_);
    }

  private:
    func f_;
    bool self_del_;
    Type* arg_;
};

template<typename Arg1, typename Arg2>
class FuncClosure2 : public Closure {
  public:
    typedef void (*func)(Arg1 a1, Arg2 a2);

    FuncClosure2(func f, Arg1 arg1, Arg2 arg2, bool self_del = false)
        : f_(f), arg1_(arg1), arg2_(arg2), self_del_(self_del) {
    }

    ~FuncClosure2() {
      if (self_del_) delete this;
    }

    void Run() {
      f_(arg1_, arg2_);
    }

  private:
    func f_;
    Arg1 arg1_;
    Arg2 arg2_;
    bool self_del_;

    DISALLOW_COPY_AND_ASSIGN(FuncClosure2);
};

template<typename Class>
class MethordClosure0 : public Closure {
  public:
    typedef void (Class::*Methord)();

    MethordClosure0(Class* obj, Methord m)
        : obj_(obj), m_(m) {
    }

    void Run() {
      (obj_->*m_)();
    }

  private:
    Class* obj_;
    Methord m_;

    DISALLOW_COPY_AND_ASSIGN(MethordClosure0);
};

template<typename Class>
class MethordClosure1 : public Closure {
  public:
    typedef void (Class::*fun)(void *);
    MethordClosure1(Class* obj, fun f, void* arg)
        : obj_(obj), f_(f), arg_(arg) {
    }

    virtual void Run() {
      (obj_->*f_)(arg_);
    }

  private:
    Class* obj_;
    fun f_;
    void* arg_;

    DISALLOW_COPY_AND_ASSIGN(MethordClosure1);
};

template<typename Class>
MethordClosure0<Class>* NewMethordClosure0(
    Class * obj, typename MethordClosure0<Class>::Methord m) {
  return new MethordClosure0<Class>(obj, m);
}

template<typename Class>
MethordClosure1<Class>* NewMethordClosure1(
    Class* obj, typename MethordClosure1<Class>::fun f, void* arg) {
  return new MethordClosure1<Class>(obj, f, arg);
}

#endif
